package com.gitee.apanlh.util.io;

import com.gitee.apanlh.exp.NotFoundException;
import com.gitee.apanlh.exp.StreamReadException;
import com.gitee.apanlh.util.base.CollUtils;
import com.gitee.apanlh.util.encode.CharsetCode;
import com.gitee.apanlh.util.unit.BuffSize;
import com.gitee.apanlh.util.valid.ValidParam;

import java.io.BufferedReader;
import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.Reader;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.function.Consumer;

/**
 * 	行迭代器,读取使用迭代器方式
 * 	<br>需要自行关闭流
 *	<br>如果迭代器未找到元素时才将会自动关闭流
 * 	&#064;example
 *   <pre>
 *   {@code
 *   try{
 *    FileLineIterator fli = new FileLineIterator(filePath/File/FileInputStream/Reader);
 *    while (fli.hasNext()) {
 *   	String str = fli.next();
 *     }
 *    } finally {
 *      fli.close();
 *    }
 *   }
 *   </pre>
 *    @author Pan
 */
public class ReadLineIterator implements Iterator<String>, Closeable {
	
	/** 缓冲读取流 */
	private BufferedReader reader;
	/** 文件流 */
	private FileInputStream fis;
	/** 字符集编码 */
	private String charset;
	/** 缓冲长度 */
	private int bufferSize;
	/** 行内容 */
	private String content;
	/** 行总数 */
	private int lineCount;
	/** 是否存在下一行 */
	private boolean hasNext;
	
	/**
	 * 	默认构造函数
	 * 	
	 * 	@author Pan
	 */
	ReadLineIterator() {
		super();
	}
	
	/**	
	 * 	构造函数-根据文件路径构建
	 * 	<br>默认8K缓冲区大小
	 * 	<br>默认系统字符集编码
	 * 
	 * 	@author Pan
	 * 	@param 	filePath	文件路径
	 */
	public ReadLineIterator(String filePath) {
		this(new File(filePath), CharsetCode.getDefaultToString(), BuffSize.SIZE_8K);
	}
	
	/**	
	 * 	构造函数-根据文件路径构建
	 * 	<br>自定义缓冲区大小
	 * 	<br>自定义字符集编码
	 * 
	 * 	@author Pan
	 * 	@param 	filePath	文件路径
	 * 	@param 	charset		字符集编码
	 * 	@param 	bufferSize	缓冲区大小
	 */
	public ReadLineIterator(String filePath, String charset, int bufferSize) {
		this(new File(filePath), charset, bufferSize);
	}
	
	/**	
	 * 	构造函数-根据文件路径构建
	 * 	<br>默认8K缓冲区大小
	 * 	<br>默认系统字符集编码
	 * 
	 * 	@author Pan
	 * 	@param 	file		文件对象
	 */
	public ReadLineIterator(File file) {
		this(file, CharsetCode.getDefaultToString(), BuffSize.SIZE_8K);
	}
	
	/**
	 * 	构造函数-根据文件对象构建
	 * 	<br>自定义缓冲区大小
	 * 	<br>自定义字符集编码
	 * 	
	 * 	@author Pan
	 * 	@param 	file		文件对象
	 * 	@param 	charset		字符集编码
	 * 	@param 	bufferSize	缓冲区大小
	 */
	public ReadLineIterator(File file, String charset, int bufferSize) {
		this(FileIOUtils.getInput(file), charset, bufferSize);
	}
	
	/**
	 * 	构造函数-根据文件输入流
	 * 	<br>默认8K缓冲区大小
	 * 	<br>默认系统字符集编码
	 * 	
	 * 	@author Pan
	 * 	@param 	fis			文件输入流
	 */
	public ReadLineIterator(FileInputStream fis) {
		this(fis, CharsetCode.getDefaultToString(), BuffSize.SIZE_8K);
	}
	
	/**
	 * 	构造函数-根据文件输入流
	 * 	<br>自定义缓冲区大小
	 * 	<br>自定义字符集编码
	 * 	
	 * 	@author Pan
	 * 	@param 	fis			文件输入流
	 * 	@param 	charset		字符集编码
	 * 	@param 	bufferSize	缓冲区大小
	 */
	public ReadLineIterator(FileInputStream fis, String charset, int bufferSize) {
		this.charset = charset;
		this.bufferSize = bufferSize;
		this.fis = fis;
		open();
	}
	
	/**
	 * 	构造函数-根据读取流
	 * 	<br>默认8K缓冲区大小
	 * 	
	 * 	@author Pan
	 * 	@param 	reader		读取流
	 */
	public ReadLineIterator(Reader reader) {
		this(reader, BuffSize.SIZE_8K);
	}
	
	/**
	 * 	构造函数-根据读取流
	 * 	<br>自定义缓冲区大小
	 * 	
	 * 	@author Pan
	 * 	@param 	reader		读取流
	 * 	@param 	bufferSize	缓冲区大小
	 */
	public ReadLineIterator(Reader reader, int bufferSize) {
		this.bufferSize = bufferSize;
		if (reader instanceof BufferedReader) {
			this.reader = (BufferedReader) reader;
		} else {
			this.reader = new BufferedReader(reader, bufferSize);
		}
	}
	
	/**	
	 * 	读取文件开启读取流
	 * 	<br>如果获取字符集编码为空,默认设置系统字符集编码
	 * 	
	 * 	@author Pan
	 */
	private void open() {
		try {
			this.reader = IOUtils.getReader(fis, CharsetCode.getCharset(charset, CharsetCode.CHARSET_DEFAULT), bufferSize);
		} catch (Exception e) {
			IOUtils.close(reader);
			throw new NotFoundException(e.getMessage(), e);
		}
	}
	
	/**	
	 * 	将读取文件并保存至集合中(有序)
	 * 	
	 * 	@author Pan
	 * 	@return	List
	 */
	public List<String> getLines() {
		List<String> newArrayList = CollUtils.newArrayList();
		while (hasNext()) {
			newArrayList.add(next());
		}
		return newArrayList;
	}
	
	/**
	 * 	验证是否存在下一个元素
	 * 	<br>如果不存在则自动关闭读取流
	 * 	<br>出现异常将自动关闭流
	 *
	 *	@author Pan
	 */
	@Override
	public boolean hasNext() {
		try {
			this.content = this.reader.readLine();
			hasNext = ValidParam.isNotNull(this.content);
			if (hasNext) {
				lineCount++;
			} else {
				close();
			}
			return hasNext;
		} catch (Exception e) {
			close();
			throw new StreamReadException(e.getMessage(), e);
		}
	}
	
	/**
	 * 	获取元素
	 * 	
	 * 	@author Pan
	 * 	@return	String
	 */
	@Override
	public String next() {
		if (!hasNext) {
			throw new NoSuchElementException("no more lines");
		}
		return this.content;
	}
	
	@Override
	public void remove() {
		//	不执行
	}
	
	@Override
	public void forEachRemaining(Consumer<? super String> action) {
		Iterator.super.forEachRemaining(action);
	}
	
	/**
	 * 	关闭读取流
	 * 	
	 * 	@author Pan
	 */
	@Override
	public void close() {
		content = null;
		IOUtils.close(this.reader);
	}
	
	/**		
	 * 	获取读取的行总数
	 * 	
	 * 	@author Pan
	 * 	@return	int
	 */
	public int getLineCount() {
		return lineCount;
	}
}
